package com.muy.redis.common.dialog;

import com.alibaba.fastjson.JSON;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.project.Project;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.muy.redis.utils.MrRedisConnectionUtils;
import com.muy.redis.utils.RedisPoolManager;
import com.muy.redis.view.component.MrRedisEditorJpanelLeft;
import com.muy.redis.view.window.redis.bean.MrRedisDb;
import com.muy.redis.view.window.redis.enums.RedisValueTypeEnum;
import com.muy.redis.view.window.redis.enums.ValueFormatEnum;
import org.apache.batik.ext.swing.DoubleDocument;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import redis.clients.jedis.Jedis;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.function.Function;

import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE;
import static com.muy.redis.view.window.redis.view.EditorTextFieldManager.createEditorTextField;
import static com.muy.redis.view.window.redis.view.EditorTextFieldManager.formatValue;

/**
 * @Author jiyanghuang
 * @Date 2023/9/26 22:09
 */
public class MrRedisNewKeyDialog implements DialogFormMark, Disposable {


    private CardLayout cardLayout;

    // 选中的数据类型
    private RedisValueTypeEnum selectedType;

    /**
     * key 输入框
     */
    private JTextField keyTextField;

    /**
     * zset score
     */
    private JTextField scoreTextField;

    /**
     * hash field
     */
    private JTextField fieldTextField;

    /**
     * Reload after adding the key
     */
    private boolean reloadSelected;

    private final Project project;

    private JPanel zsetValuePanel;
    private JPanel hashValuePanel;

    private EditorTextField stringValueTextArea;
    private EditorTextField listValueTextArea;
    private EditorTextField setValueTextArea;
    private EditorTextField zsetValueTextArea;
    private EditorTextField hashValueTextArea;

    private MrRedisEditorJpanelLeft mrRedisEditorJpanelLeft;

    public MrRedisNewKeyDialog(Project project, MrRedisEditorJpanelLeft mrRedisEditorJpanelLeft) {
        this.project = project;
        this.mrRedisEditorJpanelLeft = mrRedisEditorJpanelLeft;
    }

    @Override
    public Project getProject() {
        return project;
    }

    @Override
    public JComponent jComponent() {
        JPanel keyPanel = createKeyPanel();
        JPanel valuePanel = createValuePanel();
        JPanel typePanel = createTypePanel(valuePanel);

        JPanel keyAndTypePanel = new JPanel(new BorderLayout());
        keyAndTypePanel.add(keyPanel, BorderLayout.NORTH);
        keyAndTypePanel.add(typePanel, BorderLayout.SOUTH);

        JBCheckBox reloadCheckBox = new JBCheckBox("Reload after adding the key", reloadSelected);
        reloadCheckBox.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                reloadSelected = reloadCheckBox.isSelected();
//                propertyUtil.setReloadAfterAddingTheKey(reloadSelected);
            }
        });
        JPanel reloadPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        reloadPanel.add(reloadCheckBox);

        JPanel container = new JPanel(new BorderLayout());
        container.setMinimumSize(new Dimension(500, 250));
        container.add(keyAndTypePanel, BorderLayout.NORTH);
        container.add(valuePanel, BorderLayout.CENTER);
        container.add(reloadPanel, BorderLayout.AFTER_LAST_LINE);

        return container;
    }

    @Override
    public <T extends DialogFormMark> Function<T, Pair<Boolean, String>> okFun() {
        return (form) -> {
            try {
                RedisPoolManager redisPoolManager = MrRedisConnectionUtils.findRedisPoolManager(mrRedisEditorJpanelLeft.getMrRedisConnectionParam());
                MrRedisDb dbInfo = mrRedisEditorJpanelLeft.getMrRedisDb();
                String key = keyTextField.getText();
                if (StringUtils.isEmpty(key)) {
                    ErrorDialog.show("Key can not be empty");
                    return Pair.of(false, "Key can not be empty");
                }

                String valueString;
                // 判断数据类型, 并存入
                switch (selectedType) {
                    case String:
                        valueString = stringValueTextArea.getText();
                        if (StringUtils.isEmpty(valueString)) {
                            ErrorDialog.show("Value can not be empty");
                            return Pair.of(false, null);
                        } else {
                            redisPoolManager.set(key, valueString, 0, dbInfo.getIndex());
                            // 关闭对话框
//                            newKeyDialog.close(OK_EXIT_CODE);
                            if (reloadSelected) {
                                // 重新渲染keyTree
                                mrRedisEditorJpanelLeft.resetPageIndex();
                                mrRedisEditorJpanelLeft.renderKeyTree();
                            }
                        }
                        break;

                    case List:
                        valueString = listValueTextArea.getText();
                        if (StringUtils.isEmpty(valueString)) {
                            ErrorDialog.show("Value can not be empty");
                        } else {
                            try {
                                java.util.List<String> strings = JSON.parseArray(valueString, String.class);
                                redisPoolManager.lpush(key, strings.toArray(new String[]{}), dbInfo.getIndex());
                            } catch (Exception exception) {
                                redisPoolManager.lpush(key, new String[]{valueString}, dbInfo.getIndex());
                            }
                            // 关闭对话框
//                            newKeyDialog.close(OK_EXIT_CODE);
                            if (reloadSelected) {
                                // 重新渲染keyTree
                                mrRedisEditorJpanelLeft.resetPageIndex();
                                mrRedisEditorJpanelLeft.renderKeyTree();
                            }
                        }
                        break;

                    case Set:
                        valueString = setValueTextArea.getText();
                        if (StringUtils.isEmpty(valueString)) {
                            ErrorDialog.show("Value can not be empty");
                        } else {
                            try {
                                java.util.List<String> strings = JSON.parseArray(valueString, String.class);
                                redisPoolManager.sadd(key, dbInfo.getIndex(), strings.toArray(new String[]{}));
                            } catch (Exception exception) {
                                redisPoolManager.sadd(key, dbInfo.getIndex(), valueString);
                            }
                            // 关闭对话框
//                            newKeyDialog.close(OK_EXIT_CODE);
                            if (reloadSelected) {
                                // 重新渲染keyTree
                                mrRedisEditorJpanelLeft.resetPageIndex();
                                mrRedisEditorJpanelLeft.renderKeyTree();
                            }
                        }
                        break;

                    case Zset:
                        valueString = zsetValueTextArea.getText();
                        String score = scoreTextField.getText();
                        if (StringUtils.isEmpty(valueString)) {
                            ErrorDialog.show("Value can not be empty");
                        } else if (StringUtils.isEmpty(score)) {
                            ErrorDialog.show("Score can not be empty");
                        } else {
                            try (Jedis jedis = redisPoolManager.getJedis(dbInfo.getIndex())) {
                                if (jedis != null) {
                                    jedis.zadd(key, Double.parseDouble(score), valueString);
                                }
                            }
                            // 关闭对话框
//                            newKeyDialog.close(OK_EXIT_CODE);
                            if (reloadSelected) {
                                // 重新渲染keyTree
                                mrRedisEditorJpanelLeft.resetPageIndex();
                                mrRedisEditorJpanelLeft.renderKeyTree();
                            }
                        }
                        break;

                    default:
                        valueString = hashValueTextArea.getText();
                        String field = fieldTextField.getText();
                        if (StringUtils.isEmpty(valueString)) {
                            ErrorDialog.show("Value can not be empty");
                        } else if (StringUtils.isEmpty(field)) {
                            ErrorDialog.show("Field can not be empty");
                        } else {
                            redisPoolManager.hset(key, field, valueString, dbInfo.getIndex());
                            // 关闭对话框
//                            newKeyDialog.close(OK_EXIT_CODE);
                            if (reloadSelected) {
                                // 重新渲染keyTree
                                mrRedisEditorJpanelLeft.resetPageIndex();
                                mrRedisEditorJpanelLeft.renderKeyTree();
                            }
                        }
                }
            } catch (Exception exp) {
                ErrorDialog.show(exp.getMessage() + "");
            }
            return Pair.of(true, null);
        };
    }

    private JPanel createValuePanel() {
        JPanel stringValuePanel = createSimpleValuePanel(RedisValueTypeEnum.String);
        JPanel listValuePanel = createSimpleValuePanel(RedisValueTypeEnum.List);
        JPanel setValuePanel = createSimpleValuePanel(RedisValueTypeEnum.Set);
        zsetValuePanel = createSimpleValuePanel(RedisValueTypeEnum.Zset);
        hashValuePanel = createSimpleValuePanel(RedisValueTypeEnum.Hash);

        JPanel zsetTypePanel = createZSetValuePanel();
        JPanel hashTypePanel = createHashValuePanel();

        cardLayout = new CardLayout();
        JPanel valuePanel = new JPanel(cardLayout);
        valuePanel.add(RedisValueTypeEnum.String.name(), stringValuePanel);
        valuePanel.add(RedisValueTypeEnum.List.name(), listValuePanel);
        valuePanel.add(RedisValueTypeEnum.Set.name(), setValuePanel);
        valuePanel.add(RedisValueTypeEnum.Zset.name(), zsetTypePanel);
        valuePanel.add(RedisValueTypeEnum.Hash.name(), hashTypePanel);
        return valuePanel;
    }

    @NotNull
    private JPanel createTypePanel(JPanel valuePanel) {
        JBLabel typeLabel = new JBLabel("Type:");
        typeLabel.setPreferredSize(new Dimension(50, 25));

        JComboBox<RedisValueTypeEnum> redisValueTypeEnumJComboBox = new JComboBox<>(RedisValueTypeEnum.values());

        redisValueTypeEnumJComboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (ItemEvent.SELECTED == e.getStateChange()) {
                    selectedType = (RedisValueTypeEnum) e.getItem();
                    cardLayout.show(valuePanel, selectedType.name());
                }
            }
        });
        redisValueTypeEnumJComboBox.setSelectedIndex(0);
        selectedType = RedisValueTypeEnum.String;

        JPanel typePanel = new JPanel(new BorderLayout());
        typePanel.add(typeLabel, BorderLayout.WEST);
        typePanel.add(redisValueTypeEnumJComboBox, BorderLayout.CENTER);
        return typePanel;
    }

    @NotNull
    private JPanel createKeyPanel() {
        JPanel keyPanel = new JPanel(new BorderLayout());
        keyPanel.setMinimumSize(new Dimension(300, 10));
        JBLabel keyLabel = new JBLabel("Key:");
        keyLabel.setPreferredSize(new Dimension(50, 25));
        keyPanel.add(keyLabel, BorderLayout.WEST);
        keyTextField = new JTextField();
        keyPanel.add(keyTextField, BorderLayout.CENTER);
        return keyPanel;
    }

    @NotNull
    private JPanel createZSetValuePanel() {
        JPanel scorePanel = new JPanel(new BorderLayout());
        JBLabel scoreLabel = new JBLabel("Score:");
        scoreLabel.setPreferredSize(new Dimension(50, 25));
        scorePanel.add(scoreLabel, BorderLayout.WEST);
        scoreTextField = new JTextField();
        scoreTextField.setDocument(new DoubleDocument());
        scorePanel.add(scoreTextField, BorderLayout.CENTER);

        JPanel zsetTypePanel = new JPanel(new BorderLayout());
        zsetTypePanel.add(scorePanel, BorderLayout.NORTH);
        zsetTypePanel.add(zsetValuePanel, BorderLayout.CENTER);
        return zsetTypePanel;
    }

    @NotNull
    private JPanel createHashValuePanel() {
        JPanel scorePanel = new JPanel(new BorderLayout());
        JBLabel scoreLabel = new JBLabel("Field:");
        scoreLabel.setPreferredSize(new Dimension(50, 25));
        scorePanel.add(scoreLabel, BorderLayout.WEST);
        fieldTextField = new JTextField();
        scorePanel.add(fieldTextField, BorderLayout.CENTER);

        JPanel zsetTypePanel = new JPanel(new BorderLayout());
        zsetTypePanel.add(scorePanel, BorderLayout.NORTH);
        zsetTypePanel.add(hashValuePanel, BorderLayout.CENTER);
        return zsetTypePanel;
    }

    /**
     * 创建一个value panel
     *
     * @return
     */
    @NotNull
    private JPanel createSimpleValuePanel(RedisValueTypeEnum typeEnum) {
        JPanel stringTypePanel = new JPanel(new BorderLayout());
        JComboBox<ValueFormatEnum> newKeyValueFormatEnumJComboBox = new JComboBox<>(ValueFormatEnum.values());
        switch (typeEnum) {
            case String:
                stringValueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");
                newKeyValueFormatEnumJComboBox.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        if (ItemEvent.SELECTED == e.getStateChange()) {
                            ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                            stringValueTextArea = formatValue(project, stringTypePanel, formatEnum, stringValueTextArea);
                        }
                    }
                });
                stringTypePanel.add(stringValueTextArea, BorderLayout.CENTER);
                break;
            case List:
                listValueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");
                newKeyValueFormatEnumJComboBox.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        if (ItemEvent.SELECTED == e.getStateChange()) {
                            ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                            listValueTextArea = formatValue(project, stringTypePanel, formatEnum, listValueTextArea);
                        }
                    }
                });
                stringTypePanel.add(listValueTextArea, BorderLayout.CENTER);
                break;
            case Set:
                setValueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");
                newKeyValueFormatEnumJComboBox.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        if (ItemEvent.SELECTED == e.getStateChange()) {
                            ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                            setValueTextArea = formatValue(project, stringTypePanel, formatEnum, setValueTextArea);
                        }
                    }
                });
                stringTypePanel.add(setValueTextArea, BorderLayout.CENTER);
                break;
            case Zset:
                zsetValueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");
                newKeyValueFormatEnumJComboBox.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        if (ItemEvent.SELECTED == e.getStateChange()) {
                            ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                            zsetValueTextArea = formatValue(project, stringTypePanel, formatEnum, zsetValueTextArea);
                        }
                    }
                });
                stringTypePanel.add(zsetValueTextArea, BorderLayout.CENTER);
                break;
            default:
                hashValueTextArea = createEditorTextField(project, PlainTextLanguage.INSTANCE, "");
                newKeyValueFormatEnumJComboBox.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        if (ItemEvent.SELECTED == e.getStateChange()) {
                            ValueFormatEnum formatEnum = (ValueFormatEnum) e.getItem();
                            hashValueTextArea = formatValue(project, stringTypePanel, formatEnum, hashValueTextArea);
                        }
                    }
                });
                stringTypePanel.add(hashValueTextArea, BorderLayout.CENTER);
                break;
        }

        JPanel viewAsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        viewAsPanel.add(new JBLabel("View as:"));
        viewAsPanel.add(newKeyValueFormatEnumJComboBox);

        JPanel valueLabelPanel = new JPanel(new BorderLayout());
        valueLabelPanel.add(new JBLabel("Value:"), BorderLayout.WEST);
        valueLabelPanel.add(viewAsPanel, BorderLayout.EAST);

        stringTypePanel.add(valueLabelPanel, BorderLayout.NORTH);

        return stringTypePanel;
    }

    @Override
    public void dispose() {

    }
}
